package com.demo.qqserver.service;

import com.demo.qqcommon.Message;
import com.demo.qqcommon.MessageType;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author gy
 * @date 2022/5/6
 * 该类创建 socket线程，保持 服务端 和 客户端的 通讯
 */
public class ServerConnectClientThread extends Thread {
    /**
     * socket 连接
     */
    private final Socket socket;
    /**
     * 用户名
     * 知道和谁在进行通讯
     * 客户端发送过来的 userId
     */
    private final String userId;

    /**
     * 在私聊情况下
     * 每次操作同一个 集合
     */
    private static final ArrayList<Message> messagesOneToOne = new ArrayList<>();


    public ServerConnectClientThread(Socket socket, String userId) {
        this.socket = socket;
        this.userId = userId;
    }

    public Socket getSocket() {
        return socket;
    }

    /**
     * 判断用户是否在线
     */
    public static boolean isOnline(String getter) {
        HashMap<String, ServerConnectClientThread> hm = ManageClientsThread.getHm();
        Set<String> onlineUsers = hm.keySet();
        return onlineUsers.contains(getter);
    }

    /**
     * 如果用户未在线，将消息添加到 ConcurrentHashMap<String, ArrayList<Message>>
     */


    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("服务端和客户端 " + userId + " 保持通讯，读取数据。。。");
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message msg = (Message) ois.readObject();

                // 根据msg 的类型做相应的业务处理
                if (msg.getMsgType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
                    // 客户端要获取 用户在线列表
                    /*
                    在线列表形式 100 200 300 400  以" " 分割
                     */
                    System.out.println(msg.getSender() + "要在线用户列表");
                    String onlineUsers = ManageClientsThread.getOnlineUsers();

                    // 返回message
                    // 构建一个Message 对象，返回给客户端
                    Message msg2 = new Message();
                    msg2.setMsgType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
                    msg2.setContent(onlineUsers);
                    // 发送者 和 接收者 是同一个人
                    msg2.setGetter(msg.getSender());

                    // 返回给客户端
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(msg2);

                } else if (msg.getMsgType().equals(MessageType.MESSAGE_COMM_MES)) {
                    if (isOnline(msg.getGetter())) {
                        // 根据msg 对象 获取 getter id ，然后再得到对应的线程
                        Socket socket = ManageClientsThread.getServerConnectClientThread(msg.getGetter()).getSocket();
                        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    /*
                    转发提示：如果客户不在线，可以保存到数据库，这样就可以实现离线留言了
                     */
                        oos.writeObject(msg);
                    } else {
                        // 如何才能拿到保存数据的 db
                        ConcurrentHashMap<String, ArrayList<Message>> offlineDB = QQServer.getOfflineDB();
                        // 保证每次都往 同一个集合里面放信息
                        messagesOneToOne.add(msg);
                        offlineDB.put(msg.getGetter(), messagesOneToOne);
                    }
                } else if (msg.getMsgType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
                    // 拿到 除了自己之外的所有socket 然后 进行发送消息
                    HashMap<String, ServerConnectClientThread> hm = ManageClientsThread.getHm();

                    hm.keySet().stream()
                            .filter(n -> !n.equals(msg.getSender()))
                            .forEach(n -> {
                                // 排除群发消息的 用户（自己）
                                // 拿到 非自己 的 关联的 socket
                                Socket socket = ManageClientsThread.getServerConnectClientThread(n).getSocket();
                                try {
                                    // 创建 对象输出流
                                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                                    // 开始写入数据
                                    oos.writeObject(msg);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }

                            });

                } else if (msg.getMsgType().equals(MessageType.MESSAGE_FILE_MES)) {
                    // 通过 getterId 拿到对应的 线程，将msg对象 转发
                    ObjectOutputStream oos = new ObjectOutputStream(ManageClientsThread.getServerConnectClientThread(msg.getGetter())
                            .getSocket().getOutputStream());
                    oos.writeObject(msg);


                } else if (msg.getMsgType().equals(MessageType.MESSAGE_CLIENT_EXIT)) {
                    System.out.println(msg.getSender() + "要退出系统了");
                    // 将该用户的 线程从 集合中移除
                    ManageClientsThread.removeServerConnectClientThread(msg.getSender());
                    // 关闭连接
                    socket.close();
                    // 退出线程，一定要退出，不然会有大量的IO异常
                    break;
                } else {
                    System.out.println("是其他的message类型，暂不处理。。。");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
